﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio;
using System.Web.Razor;
using System.IO;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell;
using VSLangProj80;

namespace Razor.SingleFileGenerator
{
    [ComVisible(true)]
    [Guid("35D91DE9-EE0B-4AC5-A558-5AE811F8DC90")]
    [CodeGeneratorRegistration(typeof(EmptyRazorGenerator), "Empty Razor Generator", vsContextGuids.vsContextGuidVCSProject, GeneratesDesignTimeSource = true)]
    [ProvideObject(typeof(EmptyRazorGenerator))]
    public class EmptyRazorGenerator : IVsSingleFileGenerator
    {
        public int DefaultExtension(out string pbstrDefaultExtension)
        {
            pbstrDefaultExtension = ".g.cs";
            return VSConstants.S_OK;
        }

        public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] rgbOutputFileContents, out uint pcbOutput, IVsGeneratorProgress pGenerateProgress)
        {
            var host = new RazorEngineHost(new CSharpRazorCodeLanguage());
            var engine = new RazorTemplateEngine(host);
            var codeProvider = new CSharpCodeProvider();
            var className = Path.GetFileNameWithoutExtension(wszInputFilePath);
            
            host.DefaultClassName = className;
            host.DefaultNamespace = wszDefaultNamespace;

            GeneratorResults results = null;
            using (var reader = new StringReader(bstrInputFileContents))
            {
                results = engine.GenerateCode(reader);

                using (var writer = new StringWriter(new StringBuilder()))
                {
                    results.GeneratedCode.Namespaces[0].Types[0].IsPartial = true;
                    results.GeneratedCode.Namespaces[0].Types[0].Members.RemoveAt(0);
                    codeProvider.GenerateCodeFromCompileUnit(results.GeneratedCode, writer, new CodeGeneratorOptions());
                    writer.Flush();

                    var bytes = Encoding.UTF8.GetBytes(writer.ToString());

                    rgbOutputFileContents[0] = Marshal.AllocCoTaskMem(bytes.Length);
                    Marshal.Copy(bytes, 0, rgbOutputFileContents[0], bytes.Length);
                    pcbOutput = (uint)bytes.Length;
                    
                    return VSConstants.S_OK;
                }
            }
        }
    }
}
